#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace myrpc{
    namespace server{
        enum class VType{
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT
        };

        // rpc服务描述类 
        class ServiceDescribe {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallBack = std::function<void(const Json::Value &, Json::Value &)>;
            // 构造函数 右值引用传递参数
            ServiceDescribe(const std::string &&method, const ServiceCallBack &&cb, 
                const std::vector<std::pair<std::string, VType>> &&params_desc, VType result_type)
                :_method(std::move(method)),
                _cb(std::move(cb)),
                _params_desc(std::move(params_desc)),
                _result_type(result_type)
            {}

            // 参数检测
            bool paramscheck(const Json::Value &params){
                // 从数组中依次获取参数描述——参数名 参数类型
                for(auto &param_desc : _params_desc){
                    // 检查当前参数字段是否存在
                    if (params.isMember(param_desc.first) == false){
                        server_logger->ERROR("方法 '%s': 参数校验失败, 参数 '%s' 不存在!", _method.c_str(), param_desc.first.c_str());
                        return false;
                    }
                    // 检查当前参数类型是否正确
                    if (check(param_desc.second, params[param_desc.first]) == false){
                        server_logger->ERROR("方法 '%s': 参数校验失败, 参数 '%s' 类型错误!", _method.c_str(), param_desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            // 执行服务回调处理 获取结果
            bool callBack(const Json::Value &params, Json::Value &result){
                _cb(params, result);
                // 检查结果类型是否正确
                if (rtypecheck(result) == false){
                    server_logger->ERROR("方法 '%s': 服务回调执行失败, 返回的结果类型错误!", _method.c_str());
                    return false;
                }
                return true;
            }
            // 获取服务方法名
            const std::string &getMethod(){
                return _method;
            }

        private:
            bool rtypecheck(const Json::Value &result){
                return check(_result_type, result);
            }
            bool check(VType type, const Json::Value &val){
                switch (type)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                default:
                    return false;
                }
            }

        private:
            std::string _method;
            ServiceCallBack _cb;
            std::vector<std::pair<std::string, VType>> _params_desc;  // 建立参数名和参数类型的映射 用数组存储
            VType _result_type;
        }; 

        class SDescribeBuilder {
        public:
            void setMethod(const std::string &method){
                _method = method;
            }
            void setServiceCallBack(const ServiceDescribe::ServiceCallBack &cb){
                _cb = cb;
            }
            void setParamDescribe(const std::string &name, VType type){
                _params_desc.push_back(std::make_pair(name, type));
            }
            void setResultType(VType type){
                _result_type = type;
            }
            ServiceDescribe::ptr build(){
                return std::make_shared<ServiceDescribe>(std::move(_method), std::move(_cb), 
                    std::move(_params_desc), _result_type);
            }

        private:
            std::string _method;
            ServiceDescribe::ServiceCallBack _cb;
            std::vector<std::pair<std::string, VType>> _params_desc;  
            VType _result_type;
        };

        class ServiceManager {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            // 插入新的服务描述
            void insert(const ServiceDescribe::ptr &service_desc){
                std::unique_lock<std::mutex> lock(_mutex);
                _services.insert(std::make_pair(service_desc->getMethod(), service_desc));
                server_logger->DEBUG("成功注册新服务: '%s'", service_desc->getMethod().c_str());
            }
            // 查找目标服务描述
            ServiceDescribe::ptr select(const std::string &name){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(name);
                if (it == _services.end()){
                    return nullptr;
                }
                return it->second;
            }
            // 移除目标服务描述
            void remove(const std::string &name){
                std::unique_lock<std::mutex> lock(_mutex);
                _services.erase(name);
            }

        private:
            std::mutex _mutex;
            // 建立服务方法名 服务描述之间的映射 用哈希表存储管理
            std::unordered_map<std::string, ServiceDescribe::ptr> _services;
        };

        class RpcRouter {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter()
            :_service_manager(std::make_shared<ServiceManager>())
            {}

            // Rpc请求的回调处理
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &msg){
                Json::Value result;
                RCode rcode = RCode::RCODE_OK;   
                // 1.检查服务方法是否存在
                server_logger->INFO("RPC调用: '%s' (ID: %s)", msg->getMethod().c_str(), msg->getMsgId().c_str());
                auto service = _service_manager->select(msg->getMethod());
                if (service == nullptr){
                    rcode = RCode::RCODE_NOT_FOUND_SERVICE;
                    server_logger->ERROR("RPC调用失败: 服务 '%s' 不存在!", msg->getMethod().c_str());
                    return response(conn, msg, result, rcode);
                }
                // 2.参数校验
                server_logger->DEBUG("请求 ID: %s, 开始校验参数...", msg->getMsgId().c_str());
                if (service->paramscheck(msg->getParameters()) == false){
                    rcode = RCode::RCODE_INVALID_PARAMS;
                    server_logger->ERROR("RPC调用失败: 服务 '%s' 参数校验失败!", msg->getMethod().c_str());
                    return response(conn, msg, result, rcode);
                }
                // 3.执行服务回调处理
                server_logger->DEBUG("请求 ID: %s, 参数校验通过, 开始执行服务回调...", msg->getMsgId().c_str());
                if (service->callBack(msg->getParameters(), result) == false){
                    rcode = RCode::RCODE_INTERNAL_ERROR;
                    server_logger->ERROR("RPC调用失败: 服务 '%s' 执行内部错误!", msg->getMethod().c_str());
                    return response(conn, msg, result, rcode);
                }
                // 4.调用成功 正确获取到结果 发送正确的响应  
                server_logger->INFO("RPC调用成功: '%s' (ID: %s)", msg->getMethod().c_str(), msg->getMsgId().c_str());
                return response(conn, msg, result, rcode);
            }
            void registerService(const ServiceDescribe::ptr &service_desc){
                server_logger->INFO("注册本地服务: '%s'", service_desc->getMethod().c_str());
                _service_manager->insert(service_desc);
            }

        private:
            // 响应构建与发送
            void response(const BaseConnection::ptr &conn, RpcRequest::ptr &msg, const Json::Value res, RCode rcode){
                auto rsp_msg=MessageFactory::create<RpcResponse>();
                rsp_msg->setMsgId(msg->getMsgId());
                rsp_msg->setMsgType(MsgType::RSP_RPC);
                rsp_msg->setResult(res);
                rsp_msg->setRCode(rcode);
                server_logger->DEBUG("发送 RPC 响应 -> ID: %s, 状态码: %s", msg->getMsgId().c_str(), errReason(rcode).c_str());
                conn->send(rsp_msg);
            }

        private:
            ServiceManager::ptr _service_manager;
        };
    }
}